package com.lumlord.common.helper;

import com.lumlord.common.SmsTemplate;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.net.ssl.SSLContext;

import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 发送短信
 *
 * @author quliang
 * @version 1.0.0
 */
@Component
public class SmsHelper {
	private static Logger logger = LoggerFactory.getLogger(SmsHelper.class);
	//无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值
	private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"";
	//无需修改,用于格式化鉴权头域,给"Authorization"参数赋值
	private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"";

	//短信接收人号码
	private static final String RECEIVER_FORMAT = "+86%1$s";

	 
	
	

	/**
	 * 发送短信，指定模板
	 * @param mobilePhone 手机号
	 * @param values 发送内容，根据模板设定
	 * @param templateId 模板id
	 * @param channelNum 通道号
	 */
	public void send(String[] mobilePhone, String values[], String templateId, String channelNum) {
		if (ObjectUtils.isEmpty(mobilePhone)) {
			throw new IllegalArgumentException("mobile to argument must have text; it must not be null, empty, or blank");
		}
		if (ObjectUtils.isEmpty(templateId)) {
			throw new IllegalArgumentException("template to argument must have text; it must not be null");
		}
		//选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
		String statusCallBack = "";
		//必填,全局号码格式(包含国家码),示例:+8615123456789,多个号码之间用英文逗号分隔
		String receiver = parseReceiver(mobilePhone); //短信接收人号码
		String prase = parseValues(values);
		String body = buildRequestBody(channelNum, receiver,templateId, prase,	statusCallBack, getSignature());
		try {
			http(body);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private String parseValues(String values[]){
		String str = "[";
		for(String s : values){
			str += "\""+ s +"\",";
		}
		str = str.substring(0, str.length() -1);
		str += "]";
		return str;
	}
	
	public void send(HttpSmsReturned sms) {
		if (ObjectUtils.isEmpty(sms.getMobile())) {
			throw new IllegalArgumentException("mobile to argument must have text; it must not be null, empty, or blank");
		}
		if (ObjectUtils.isEmpty(sms.getTemplate())) {
			throw new IllegalArgumentException("template to argument must have text; it must not be null");
		}
		logger.info(sms.getMobile() +"--"+sms.getTemplate().getTemplateParas() +"--"+sms.getValues());
		//选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
		String statusCallBack = "";
		//必填,全局号码格式(包含国家码),示例:+8615123456789,多个号码之间用英文逗号分隔
		String receiver = parseReceiver(sms.getMobile()); //短信接收人号码
		SmsTemplate template = sms.getTemplate();
		String paras = parseParas(template.getTemplateParas(), sms.getValues());
		String body = buildRequestBody(template.getChannelNum(), receiver,
				template.getTemplateId(), paras,
				statusCallBack, getSignature()
		);
		try {
			http(body);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void http(String body) throws Exception {
		//请求Headers中的X-WSSE参数值
		String wsseHeader = buildWsseHeader(getKey(), getSecret());

		//如果JDK版本是1.8,可使用如下代码
		//为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
		CloseableHttpClient client = HttpClients.custom()
				.setSSLContext(sslContext())
				.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
				.build();

		HttpResponse response = client.execute(RequestBuilder.create("POST")//请求方法POST
				.setUri(getUrl())
				.addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded")
				.addHeader(HttpHeaders.AUTHORIZATION, AUTH_HEADER_VALUE)
				.addHeader("X-WSSE", wsseHeader)
				.setEntity(new StringEntity(body)).build());
		logger.info("response : "+response.toString());
		logger.info("response getEntity : "+EntityUtils.toString(response.getEntity()));
	}

	/**
	 * 构造请求Body体 for 国内短信通用模板
	 *
	 * @param sender         国内短信签名通道号或国际/港澳台短信通道号
	 * @param receiver       必填,全局号码格式(包含国家码),示例:+8615123456789,多个号码之间用英文逗号分隔
	 * @param templateId     模板ID
	 * @param templateParas  变量模板
	 * @param statusCallBack 选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
	 * @param signature      签名名称
	 * @return 请求Body, 国内短信通用模板
	 */
	private String buildRequestBody(String sender, String receiver, String templateId, String templateParas,
									String statusCallBack, String signature) {

		List<NameValuePair> keyValues = new ArrayList<NameValuePair>();

		keyValues.add(new BasicNameValuePair("from", sender));
		keyValues.add(new BasicNameValuePair("to", receiver));
		keyValues.add(new BasicNameValuePair("templateId", templateId));
		keyValues.add(new BasicNameValuePair("templateParas", templateParas));
		keyValues.add(new BasicNameValuePair("statusCallback", statusCallBack));
		if (null != signature && !signature.isEmpty()) {
			keyValues.add(new BasicNameValuePair("signature", signature));
		}
		return URLEncodedUtils.format(keyValues, "UTF-8");
	}

	/**
	 * 构造X-WSSE参数值
	 *
	 * @param appKey
	 * @param appSecret
	 * @return
	 */
	private String buildWsseHeader(String appKey, String appSecret) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
		String time = sdf.format(new Date()); //Created
		String nonce = UUID.randomUUID().toString().replace("-", ""); //Nonce

		byte[] passwordDigest = DigestUtils.sha256(nonce + time + appSecret);
		String hexDigest = Hex.encodeHexString(passwordDigest);

		//如果JDK版本是1.8,请加载原生Base64类,并使用如下代码
		// String passwordDigestBase64Str = Base64.getEncoder().encodeToString(hexDigest.getBytes()); //PasswordDigest
		//如果JDK版本低于1.8,请加载三方库提供Base64类,并使用如下代码
		String passwordDigestBase64Str = Base64.encodeBase64String(hexDigest.getBytes(Charset.forName("UTF-8"))); //PasswordDigest
		//若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正
		// passwordDigestBase64Str = passwordDigestBase64Str.replaceAll("[\\s*\t\n\r]", "");
		return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time);
	}

	/**
	 * 忽略证书信任问题
	 *
	 * @throws Exception
	 */
	private SSLContext sslContext() throws Exception {
		SSLContextBuilder builder = new SSLContextBuilder();
		builder.loadTrustMaterial(null, new SmsTrustStrategy());
		return builder.build();
	}

	private String parseReceiver(String[] mobiles) {
		StringBuilder receiver = new StringBuilder();
		for (int i = 0, len = mobiles.length; i < len; i++) {
			String mobile = mobiles[i];
			if (ObjectUtils.isEmpty(mobile)) {
				continue;
			}
			receiver.append(String.format(RECEIVER_FORMAT, mobile));
			if (i < len - 1) {
				receiver.append(",");
			}
		}
		return receiver.toString();
	}

	private String parseParas(String templateParas, String[] values) {
		if (ObjectUtils.isEmpty(templateParas) || ObjectUtils.isEmpty(values)) {
			return "";
		}
		return String.format(templateParas, values);
	}

	private class SmsTrustStrategy implements TrustStrategy {

		@Override
		public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
			return true;
		}
	}
	
	
	
	
	
	
	
	
	//短信
	private String url;
	private String sender;
	private String key;
	private String secret;
	private String signature;
	
	@Value("${lumlord.sms.url:DefaultValue}")
	public void setSmsUrl(String url) {
		this.url = url;
	}

	@Value("${lumlord.sms.sender:DefaultValue}")
	public void setSmsSender(String sender) {
		this.sender = sender;
	}

	@Value("${lumlord.sms.key:DefaultValue}")
	public void setSmsKey(String key) {
		this.key = key;
	}

	@Value("${lumlord.sms.secret:DefaultValue}")
	public void setSmsSecret(String secret) {
		this.secret = secret;
	}

	@Value("${lumlord.sms.signature:DefaultValue}")
	public void setSmsSignature(String signature) {
		this.signature = signature;
	}
	
	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getSender() {
		return sender;
	}

	public void setSender(String sender) {
		this.sender = sender;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getSecret() {
		return secret;
	}

	public void setSecret(String secret) {
		this.secret = secret;
	}

	public String getSignature() {
		return signature;
	}

	public void setSignature(String signature) {
		this.signature = signature;
	}
	
}
